--[[
    @Author       : baidwwy
    @Date         : 2021-02-11 11:49:09
    @LastEditTime : 2021-05-03 10:24:50
--]]

local _ENV = require("GGE界面")
_输入列表 = {}--记录输入框，以切换焦点
local _类型={
    '控件','输入','多行输入',
    '按钮','单选按钮','多选按钮',
    '窗口','文本','网格',
    '列表','多列列表','树形列表',
    '标签','滑块','进度',
}
GUI控件 = class("GUI控件")
GUI控件._type  = 1
function GUI控件:初始化(name,x,y,w,h,f)
    self.名称   = name
    self.x      = math.floor(x or 0)
    self.y      = math.floor(y or 0)
    self.宽度   = w or (f and f.宽度 or 窗口.宽度)
    self.高度   = h or (f and f.高度 or 窗口.高度)

    self.父控件 = f
    self.子控件 = {}
    --self.是否可见 = false
    --self.是否禁止 = false
    --self.是否实例   = false --是否已经加载

    self.矩形 = require("GGE.矩形")(0,0,self.宽度,self.高度)
    self.矩形:置颜色(255,0,0)
    --self.矩形:置坐标(self:取坐标())
end

function GUI控件:_更新(...)
    if rawget(self,"更新") then self:更新(...)end
    if self.精灵 and self.精灵.更新 then
        self.精灵:更新(...)
    end
    for i,v in ipairs(self.子控件) do
        if v.是否可见 then
            v:_更新(...)
        end
    end
end

function GUI控件:_显示(x,y)
    local _x,_y = self:取坐标()--坐标是相对的，每次获取,TODO：移动才修改
    self.矩形:置坐标(_x,_y)
    窗口:置区域(_x,_y,self.宽度,self.高度)
        if rawget(self,"精灵") then self.精灵:显示(_x,_y)end
        if rawget(self,"显示") then self:显示(_x,_y,x,y)end
        for i,v in ipairs(self.子控件) do
            if v.是否可见 then
                v:_显示(_x,_y,x,y)
            end
        end
        --self.矩形:显示()
    窗口:置区域()
end

function GUI控件:_消息事件(msg)
    if self.是否禁止 then
        return 
    end
    for i=#self.子控件,1,-1 do
        local v = self.子控件[i]
        if v.是否可见 then
            v:_消息事件(msg)
        end
    end
    
    for _,v in ipairs(msg.键盘) do
        if self:发送消息("键盘事件",table.unpack(v)) then
            v[2] = nil
        end
    end
    
    for _,v in ipairs(msg.鼠标) do
        if self:发送消息("鼠标事件",table.unpack(v)) then
            --v[2] = nil
        end
        if self._type==1 then
            local r
            if v.type==SDL.鼠标_按下 then
                if self:检查点(v.x,v.y) then
                    if v.button==SDL.BUTTON_LEFT then
                        self._ldown = v.x..v.y
                        r = self:发送消息("左键按下",v.x,v.y,msg)
                    elseif v.button==SDL.BUTTON_RIGHT then
                        self._rdown = v.x..v.y
                        r = self:发送消息("右键按下",v.x,v.y,msg)
                    end
                    if r then
                        v.x = -9999;v.y = -9999
                    end
                end
            elseif v.type==SDL.鼠标_弹起 then
                if self:检查点(v.x,v.y) then
                    if v.button==SDL.BUTTON_LEFT then
                        if self._ldown==v.x..v.y then
                            r = self:发送消息("左键弹起",v.x,v.y,msg)
                        end
                    elseif v.button==SDL.BUTTON_RIGHT then
                        if self._rdown then
                            r = self:发送消息("右键弹起",v.x,v.y,msg)
                        end
                    end
                    if r then
                        v.x = -9999;v.y = -9999
                    end
                end
                self._ldown = nil
                self._rdown = nil
            elseif v.type==SDL.鼠标_移动 then
                if self:检查点(v.x,v.y) then
                    if self:发送消息("获得鼠标",v.x,v.y,msg) then
                        v.x = -9999;v.y = -9999
                    end
                end
            -- elseif v.type==SDL.鼠标_滚轮 then
            --     print(self.父控件 and self.父控件.名称,self.名称)
            end
        end
    end
    

    if self._type==1 then
        self:发送消息("消息事件",msg)
    end
end

function GUI控件:取类型()
    return _类型[self._type]
end

function GUI控件:置精灵(v)
    if type(v)=='table' and v.显示 and v.取矩形 and v.取透明 then
        self.精灵 = v
        self.矩形 = v:取矩形():复制()
        self.宽度 = v.宽度
        self.高度 = v.高度
    else
        self.精灵 = nil
    end
    return self
end

function GUI控件:置坐标(x,y)--坐标是相对于父的
    self.x = x or 0
    self.y = y or 0
    return self
end

function GUI控件:取坐标()
    local x,y = self.x,self.y
    if self.相对坐标~=false then--如果坐标为负数，则值相对于 宽高 - 坐标
        if x<0 then
            if self.父控件 then
                x = self.父控件.宽度+x
            else
                x = self.宽度+x
            end
        end
        if y<0 then
            if self.父控件 then
                y = self.父控件.高度+y
            else
                y = self.高度+y
            end
        end
    end
    if self.父控件 then
        local px,py = self.父控件:取坐标()
        return x+px,y+py
    end
    return x,y
end

function GUI控件:置宽高(w,h)
    self.宽度 = w
    self.高度 = h
    self.矩形:置宽高(w,h)
    return self
end

function GUI控件:取宽高()
    return self.宽度,self.高度
end

function GUI控件:取坐标宽高()
    local x,y = self:取坐标()
    return x,y,self.宽度,self.高度
end

function GUI控件:置宽度(w)
    self.宽度 = w
    self.矩形:置宽高(w,self.高度)
    return self
end

function GUI控件:置高度(h)
    self.高度 = h
    self.矩形:置宽高(self.宽度,h)
    return self
end

function GUI控件:遍历()
    return next,self.子控件
end

function GUI控件:检查点(x,y)
    return self.矩形:检查点(x,y)
end

function GUI控件:检查透明(x,y)
    if self.精灵 then
        return self.精灵:取透明(x,y)~=0
    end
    return false
end

function GUI控件:置可见(val,sub)
    self.是否可见 = val==true
    if not self.是否实例 and val then
        if rawget(self, '初始化') then 
            ggexpcall(self.初始化, self)
        end
        self.是否实例 = true
    end
    if sub and (self.是否实例 or val) then
        for _,v in ipairs(self.子控件) do
            v:置可见(val,sub)
        end
    end
    return self
end

function GUI控件:置禁止(v)
    self.是否禁止 = v==true
    return self
end

function GUI控件:发送消息(name,...)
    local fun = rawget(self, name)
    if type(fun)=='function' then
        return ggexpcall(coroutine.wrap(fun), self,...)
    end
end

function GUI控件:释放(名称)
    if 名称 then
        local 控件 = self[名称]
        if 控件 then
            for i,v in ipairs(self.子控件) do
                if v == 控件 then
                    table.remove(self.子控件, i)
                    释放引用(v)
                    break
                end
            end
            self[名称] = nil
        end
    else
        for i,v in ipairs(self.子控件) do
            self[v.名称] = nil
            释放引用(v)
        end
        self.子控件 = {}
    end
end

function GUI控件:创建控件(name,x,y,w,h)
    ggeassert(not self[name],name..":此控件已存在，不能重复创建.",2)
    self[name] = GUI控件(name,x,y,w,h,self)
    table.insert(self.子控件, self[name])
    return self[name]
end

function GUI控件:创建按钮(name,x,y,w,h)
    ggeassert(not self[name],name..":此按钮已存在，不能重复创建.",2)
    self[name] = GUI按钮(name,x,y,w,h,self)
    table.insert(self.子控件, self[name])
    return self[name]
end

function GUI控件:创建多选按钮(name,x,y,w,h)
    ggeassert(not self[name],name..":此按钮已存在，不能重复创建.",2)
    self[name] = GUI多选按钮(name,x,y,w,h,self)
    table.insert(self.子控件, self[name])
    return self[name]
end

function GUI控件:创建单选按钮(name,x,y,w,h)
    ggeassert(not self[name],name..":此按钮已存在，不能重复创建.",2)
    self[name] = GUI单选按钮(name,x,y,w,h,self)
    table.insert(self.子控件, self[name])
    return self[name]
end

function GUI控件:创建窗口(name,x,y,w,h)
    ggeassert(not self[name],name..":此窗口已存在，不能重复创建.",2)
    self[name] = GUI窗口(name,x,y,w,h,self)
    table.insert(self.子控件, self[name])
    return self[name]
end

function GUI控件:创建输入(name,x,y,w,h)
    ggeassert(not(self[name] or _输入列表[name]),name..":此输入已存在，不能重复创建.",2)
    self[name] = GUI输入(name,x,y,w,h,self)
    table.insert(self.子控件, self[name])
    _输入列表[name] = 对象
    return self[name]
end

function GUI控件:创建多行输入(name,x,y,w,h)
    ggeassert(not(self[name] or _输入列表[name]),name..":此多行输入已存在，不能重复创建.",2)
    self[name] = GUI多行输入(name,x,y,w,h,self)
    table.insert(self.子控件, self[name])
    _输入列表[name] = 对象
    return self[name]
end

function GUI控件:创建文本(name,x,y,w,h)
    ggeassert(not self[name],name..":此文本已存在，不能重复创建.",2)
    self[name] = GUI文本(name,x,y,w,h,self)
    table.insert(self.子控件, self[name])
    return self[name]
end

function GUI控件:创建列表(name,x,y,w,h)
    ggeassert(not self[name],name..":此列表已存在，不能重复创建.",2)
    self[name] = GUI列表(name,x,y,w,h,self)
    table.insert(self.子控件, self[name])
    return self[name]
end

function GUI控件:创建树形列表(name,x,y,w,h)
    ggeassert(not self[name],name..":此树形列表已存在，不能重复创建.",2)
    self[name] = GUI树形列表(name,x,y,w,h,self)
    table.insert(self.子控件, self[name])
    return self[name]
end

function GUI控件:创建多列列表(name,x,y,w,h)
    ggeassert(not self[name],name..":此多列列表已存在，不能重复创建.",2)
    self[name] = GUI多列列表(name,x,y,w,h,self)
    table.insert(self.子控件, self[name])
    return self[name]
end

function GUI控件:创建进度(name,x,y,w,h)
    ggeassert(not self[name],name..":此进度已存在，不能重复创建.",2)
    self[name] = GUI进度(name,x,y,w,h,self)
    table.insert(self.子控件, self[name])
    return self[name]
end

function GUI控件:创建网格(name,x,y,w,h)
    ggeassert(not self[name],name..":此网格已存在，不能重复创建.",2)
    self[name] = GUI网格(name,x,y,w,h,self)
    table.insert(self.子控件, self[name])
    return self[name]
end

function GUI控件:创建标签(name,x,y,w,h)
    ggeassert(not self[name],name..":此标签已存在，不能重复创建.",2)
    self[name] = GUI标签(name,x,y,w,h,self)
    table.insert(self.子控件, self[name])
    return self[name]
end

function GUI控件:创建滑块(name,x,y,w,h)
    ggeassert(not self[name],name..":此滑块已存在，不能重复创建.",2)
    self[name] = GUI滑块(name,x,y,w,h,self)
    table.insert(self.子控件, self[name])
    return self[name]
end